import json
class BetterSerializable(object):
    def __init__(self, *args):
        self.args = args
    
    def serialize(self):
        return json.dumps({
            'class': self.__class__.__name__,
            'args': self.args,
        })

    # def __repr__(self):
    #     return 'BetterSerializable(%d, %d)' % (self.x, self.y)

registry = {}
def register_class(target_class):
    registry[target_class.__name__] = target_class

def deserialize(data):
    params = json.loads(data)
    name = params['class']
    target_class = registry[name]
    return target_class(*params['args'])

class EvenBetterPoint2D(BetterSerializable):
    def __init__(self, x, y):
        super().__init__(x, y)
        self.x = x
        self.y = y
    
    def __repr__(self):
        return 'EvenBetterPoint2D(%d, %d)' % (self.x, self.y)

register_class(EvenBetterPoint2D)

point = EvenBetterPoint2D(5, 3)
data = point.serialize()
after = deserialize(data)
print("After %s" % after)

# use meta to execute register_class

class Meta(type):
    def __new__(meta, name, bases, class_dict):
        cls = type.__new__(meta, name, bases, class_dict)
        register_class(cls)
        return cls

class RegisteredSerializable(BetterSerializable, metaclass=Meta):
    pass

class Vector3D(RegisteredSerializable):
    def __init__(self, x, y, z):
        super().__init__(x,y,z)
        self.x, self.y, self.z = x, y, z

    def __repr__(self):
        return 'Vector3D(%d, %d, %d)' % (self.x, self.y, self.z)

v = Vector3D(10,-7, 3)
data = v.serialize()
after = deserialize(data)
print("After %s" % after)
